/*
*  SkyDecoder.h
*  
*
*  Created by Alexander Trutchenko on 11/02/12.
*  Copyright 2012 Free Team. All rights reserved.
*
*/

#ifndef __Sky_Decoder_h__
#define __Sky_Decoder_h__

#include "SkyBufferHeader.h"

#include "SkyOpenALInclude.h"
#include "SkyFile.h"

#include "SkyAssert.h"

#include <set>
#include <string>

#include "stdlib.h"

namespace sky {

////////////////////////////////////////////////////////
//
/** SkyMemoryWrapper
*  
*/
////////////////////////////////////////////////////////

class SkyMemoryWrapper
{
	unsigned int _size; 
public:
	SkyMemoryWrapper(unsigned int size):_size(size) {;}
	virtual ~SkyMemoryWrapper() {;}

public:
	inline unsigned int size() const { return _size; } //size in bytes
	virtual ALvoid* data() = 0;
};

template <typename T>
class SkyCppArrayWrapper : public SkyMemoryWrapper
{
	T* _data;
public:
	SkyCppArrayWrapper(T* data, unsigned int size): SkyMemoryWrapper(size), _data(data) 
	{
		SkyAssert(_data != NULL, "SkyCppArrayWrapper(): Data must not be NULL!");
	}
	virtual ~SkyCppArrayWrapper() { delete [] _data; }

	virtual ALvoid* data() { return (ALvoid*)_data; }
};

template <typename T>
class SkyCArrayWrapper : public SkyMemoryWrapper
{
	T* _data;
public:
	SkyCArrayWrapper(T* data, unsigned int size): SkyMemoryWrapper(size),_data(data) 
	{
		SkyAssert(_data != NULL, "SkyCArrayWrapper(): Data must not be NULL!");
	}
	virtual ~SkyCArrayWrapper() { free(_data); }

	virtual ALvoid* data() { return (ALvoid*)_data; }
};

////////////////////////////////////////////////////////
//
/** SkySoundDecoder
*  
*/
////////////////////////////////////////////////////////

class SkySoundDecoder
{
protected:
	bool _isValid;

protected:
	SkySoundDecoder(): _isValid(true) {;}
	virtual ~SkySoundDecoder() {;}

public:
	virtual bool isValid() const { return _isValid; }

	virtual void onOpenOutputDevice() {;}
	virtual void onCloseOutputDevice() {;}
	virtual void onSetCurrentContext() {;}
	virtual void onClearCurrentContext() {;}

}; //class SkyStaticDecoder

////////////////////////////////////////////////////////
//
/** SkyStaticDecoder
*  
*/
////////////////////////////////////////////////////////

class SkyBufferHeader;
class SkyFileData;

class SkyStaticDecoder : public SkySoundDecoder
{
protected:
	std::set<std::string> _extentions;
public:
	bool canFileBeDecoded(const std::string& extention, const ALvoid *data, ALsizei fileSize)
	{
		if (_extentions.find(extention) == _extentions.end())
			return false;
		return true;
	}
	virtual ALuint getBufferIDFromFileData(const SkyFileData& fileData) const = 0; 
	virtual SkyMemoryWrapper* getPCMDataFromFileData(const SkyFileData& fileData, SkyBufferHeader& header) const = 0;

}; //class SkyStaticDecoder


////////////////////////////////////////////////////////
//
/** SkyStreamData
*  
*/
////////////////////////////////////////////////////////

class SkyBufferManager;

class SkyStreamData
{
protected:
	SkyBufferManager* _bufferManager;
	bool _isValid;
	SkyBufferHeader _header;

public:
	SkyStreamData(SkyBufferManager* bufferManager, const char* name): _bufferManager(bufferManager), _isValid(true), _header(name) {;}
	virtual ~SkyStreamData() {;}

public:
	inline bool isValid() const { return _isValid; }

	const SkyBufferHeader& header() const { return _header; }
	virtual bool isSeekable() const = 0;
	virtual void seek(float position) = 0; // position = [0.f .. 1.f]
	virtual float position() const = 0; // position = [0.f .. 1.f]
	virtual const char* name() const = 0; // any key name
	virtual unsigned int readBlock(void* buffer, int desirableDecodeSize) = 0;

}; //class SkyStreamDecoder


////////////////////////////////////////////////////////
//
/** SkyStreamFileData
*  
*/
////////////////////////////////////////////////////////

class SkyStreamFileData : public SkyStreamData
{
protected:
	const SkyFileData* _fileData; //weak ref
	float _playbackCursor;

public:
	unsigned int _dataCursor;

public:
	SkyStreamFileData(SkyBufferManager* bufferManager, const SkyFileData* fileData);
	SkyStreamFileData(SkyBufferManager* bufferManager, const char* file);
	virtual ~SkyStreamFileData();

public:
	const char* name() const { return file(); }
	const char* file() const { return _fileData->file(); }
	const unsigned char* data() const { return _fileData->data(); }
	inline unsigned int dataSize() const { return _fileData->size(); }
	virtual float position() const { return _playbackCursor; } // position = [0.f .. 1.f]

}; //class SkyStreamDecoder

////////////////////////////////////////////////////////
//
/** SkyStreamDecoder
*  
*/
////////////////////////////////////////////////////////

class SkyStreamDecoder : public SkySoundDecoder
{
protected:
	SkyStreamData* _streamData;

public:
	SkyStreamDecoder(SkyStreamData* streamData): _streamData(streamData) {;}
	virtual ~SkyStreamDecoder() { delete _streamData; }

public:
	const SkyStreamData* streamData() const { return _streamData; }
	bool isSeekable() const { return _streamData->isSeekable(); }

	virtual void seek(float position) = 0; // position = [0.f .. 1.f]
	virtual SkyMemoryWrapper* readBlock(int desirableDecodeSize) = 0; // returns decoded size

}; //class SkyStreamDecoder

////////////////////////////////////////////////////////
//
/** SkyStreamDecoderFactory
*  
*/
////////////////////////////////////////////////////////

class SkyStreamDecoderFactory
{
public:
	SkyStreamDecoderFactory() {;}
	virtual ~SkyStreamDecoderFactory() {;}

public: 
	virtual SkyStreamDecoder* createDecoder(SkyStreamData* streamData) const = 0;
	virtual SkyStreamFileData* createStreamFileData(SkyBufferManager* bufferManager, const char* file) const = 0;
};

////////////////////////////////////////////////////////
//
/** Util functions
*  
*/
////////////////////////////////////////////////////////

class SkyBufferManager;

extern void addDecoders(SkyBufferManager* bufManager);

} // namespace sky

#endif //__Sky_Decoder_h__
